import pygame
from pygame.locals import *

pygame.init()

import lib


import os
import json


GROUPS = ('Solid','Background','Foreground')

TILE_NAMES = {'Solid':('Center','Left-Side','Right-Side','Top',
                      'Bottom','Left-Top-Outside-Corner',
                      'Right-Top-Outside-Corner',
                      'Left-Bottom-Outside-Corner',
                      'Right-Bottom-Outside-Corner',
                      'Left-Top-Inside-Corner',
                      'Right-Top-Inside-Corner',
                      'Left-Bottom-Inside-Corner',
                      'Right-Bottom-Inside-Corner')}


class LevelEditor:
  def __init__(self):
    self.screen = pygame.display.set_mode([720,520],0,32)
    
    pygame.display.set_caption('Foxen - Level Editor')
    
    self.screen_pos        = [0,35]
    
    self.level_name        = ''
    
    self.current_group     = 0
    self.current_tile_name = 0
    
    self.placement_mode    = 'Place Terrain'
    
    self.level_data        = {}
    self.images            = {}
    
    self.load_level('test')
    
    if len(self.level_data.keys()) == 0:
      self.new_level()
    
    self.status_message = 'Started; Editing Level ' + str(self.level_name)
    
    self.timer = pygame.time.Clock()
  
  def add_empty_cell(self):
    new_cell = {'Terrain':{'Solid':     [],
                           'Background':[],
                           'Foreground':[]},
                'Baddies':[],
                'Widgets':[]}
    
    for column in range(25):
      new_cell['Terrain']['Solid'].append({'Name':'Top','Position':[column,46]})
      
      for row in range(47,50):
        new_cell['Terrain']['Solid'].append({'Name':'Center','Position':[column,row]})
    
    self.level_data['Cells'].append(new_cell)
  
  def refresh_images(self):
    self.images = {'Player':lib.data.load_player_images('Trixie'),
                   'Baddies':[],'Items':[],
                   'Terrain':lib.data.load_terrain_images(self.level_data['Metadata']['Tileset'])}
  
  def new_level(self,name=None):
    if str(self.level_name) != '':
      self.save_level()
    
    if   name != None:
      self.level_name = name
    elif str(self.level_name) == '':
      self.level_name = 'test'
    
    self.level_data = {'Metadata':{'Name':str(self.level_name),'Length':10,
                                   'Tileset':'grass','Player Start':[0,[0,0]]},
                                   'Cells':[]}
    
    self.refresh_images()
    
    self.screen_pos = [0,36]
    
    for cell in range(10):
      self.add_empty_cell()
    
    self.status_message = 'New Level Named ' + str(self.level_name)
  
  def load_level(self,name):
    self.save_level()
    
    self.level_name = name
    
    self.reload_level()
    
    if len(self.level_data.keys()) == 0:
      self.new_level(name)
      
      self.status_message = ('Level ' + str(name) + ' does not exist! Creating new level...')
  
  def reload_level(self):
    try:
      file_path  = os.path.relpath(os.path.join(__file__,'..','data'))
      file_path  = os.path.join(file_path,'level',(str(self.level_name)+'.lvl'))
      
      lvl_file   = open(file_path,'r')
      
      self.level_data = json.load(lvl_file)
      
      lvl_file.close()
      
      self.refresh_images()
      
      self.screen_pos = [0,36]
      
      self.status_message = 'Reloaded Level from File'
    except Exception:
      self.level_data = {}
      
      self.status_message = 'Error Reloading Level'
  
  def save_level(self):
    try:
      file_path  = os.path.relpath(os.path.join(__file__,'..','data'))
      file_path  = os.path.join(file_path,'level',(str(self.level_name)+'.lvl'))
      
      lvl_file   = open(file_path,'w')
      
      json.dump(self.level_data,lvl_file,indent=2)
      
      lvl_file.close()
      
      self.status_message = 'Level ' + str(self.level_name) + ' Saved'
    except IOError:
      self.status_message = 'Error Saving Level'
  
  def go(self):
    while True:
      self.timer.tick(10)
      
      self.step()
  
  def get_terrain_at(self,group,cell,coords):
    if group in self.level_data['Cells'][cell]['Terrain'].keys():
      for block in self.level_data['Cells'][cell]['Terrain'][group]:
        bl_coords = block['Position']
        
        if bl_coords[0] == coords[0] and bl_coords[1] == coords[1]:
          return block
    
    return None
  
  def remove_terrain_at(self,group,cell,coords):
    current_tile = self.get_terrain_at(group,cell,coords)
    
    if current_tile:
      self.level_data['Cells'][cell]['Terrain'][group].remove(current_tile)
  
  def set_terrain_at(self,group,name,cell,coords):
    self.remove_terrain_at(group,cell,coords)
    
    new_tile = {'Position':tuple(coords),'Name':name}
    
    self.level_data['Cells'][cell]['Terrain'][group].append(new_tile)
  
  def group_name(self):
    return GROUPS[self.current_group]
  
  def tile_name(self):
    return TILE_NAMES[self.group_name()][self.current_tile_name]
  
  def step(self):
    for event in pygame.event.get():
      if event.type == QUIT:
        pygame.quit()
        exit()
      elif event.type == KEYDOWN:
        if   event.key == K_ESCAPE:
          pygame.quit()
          exit()
        elif event.key == K_F2:
          self.current_group -= 1
          
          if self.current_group == -1:
            self.current_group = (len(GROUPS) - 1)
        
        ###--- GROUP CHANGES ---###
        if event.key == K_F2:
          self.current_group -= 1
          
          if self.current_group == -1:
            self.current_group = (len(GROUPS) - 1)
        elif event.key == K_F1:
          self.current_group -= 2
          
          if self.current_group == -1:
            self.current_group = (len(GROUPS) - 1)
          if self.current_group == -2:
            self.current_group = (len(GROUPS) - 2)
        elif event.key == K_F3:
          self.current_group += 1
          
          if self.current_group == len(GROUPS):
            self.current_group = 0
        elif event.key == K_F4:
          self.current_group += 2
          
          if self.current_group == len(GROUPS):
            self.current_group = 0
          if self.current_group == (len(GROUPS) + 1):
            self.current_group = 1
        
        if event.key in (K_F1,K_F2,K_F3,K_F4):
          self.status_message = "Changed tile group to " + self.group_name()
        
        ###--- TILE NAME CHANGES ---###
        if event.key == K_F7:
          self.current_tile_name -= 1
          
          if self.current_tile_name == -1:
            self.current_tile_name = len(TILE_NAMES[self.group_name()])-1
        elif event.key == K_F6:
          self.current_tile_name -= 2
          
          if self.current_tile_name == -1:
            self.current_tile_name = len(TILE_NAMES[self.group_name()])-1
          if self.current_tile_name == -2:
            self.current_tile_name = len(TILE_NAMES[self.group_name()])-2
        elif event.key == K_F8:
          self.current_tile_name += 1
          
          if self.current_tile_name == len(TILE_NAMES[self.group_name()]):
            self.current_tile_name = 0
        elif event.key == K_F9:
          self.current_tile_name += 2
          
          if self.current_tile_name == len(TILE_NAMES[self.group_name()]):
            self.current_tile_name = 0
          if self.current_tile_name == len(TILE_NAMES[self.group_name()]) + 1:
            self.current_tile_name = 1
        
        if event.key in (K_F6,K_F7,K_F8,K_F9):
          self.status_message = 'Now Placing Tile: ' + self.tile_name()
        
        ###--- PLACEMENT MODES ---###
        if event.key == K_1:
          self.status_message = 'Now Placing Terrain'
          self.placement_mode = 'Place Terrain'
        elif event.key == K_2:
          self.placement_mode = 'Place Baddie'
        elif event.key == K_3:
          self.placement_mode = 'Place Item'
        elif event.key == K_4:
          self.placement_mode = 'Place Prop'
        elif event.key == K_5:
          self.status_message = 'Now Placing Player Start Point'
          self.placement_mode = 'Place Player Start'
        
        
        ###--- FILE COMMANDS ---###
        if event.key == K_s and event.mod & KMOD_LCTRL:
          self.save_level()
        elif event.key == K_r and event.mod & KMOD_LCTRL:
          self.reload_level()
        elif event.key == K_n and event.mod * KMOD_LCTRL:
          self.new_level()
        
        ###--- SCROLLING ---###
        
        if   event.key == K_LEFT:
          self.screen_pos[0] -= 1
        elif event.key == K_RIGHT:
          self.screen_pos[0] += 1
        elif event.key == K_UP:
          self.screen_pos[1] -= 1
        elif event.key == K_DOWN:
          self.screen_pos[1] += 1
    
    keys_pressed = pygame.key.get_pressed()
    
    if keys_pressed[K_LEFT]:
      self.screen_pos[0] -= 1
    if keys_pressed[K_RIGHT]:
      self.screen_pos[0] += 1
    if keys_pressed[K_UP]:
      self.screen_pos[1] -= 1
    if keys_pressed[K_DOWN]:
      self.screen_pos[1] += 1
    
    
    self.screen.fill((0,160,200))
    
    base_cell = (self.screen_pos[0] + 9) // 25
    
    camera_pos = list(self.screen_pos)
    
    camera_pos[0] -= (base_cell*25)
    
    self.screen.fill((0,140,210))
    
    player_image = self.images['Player']['Normal']['Idle']
    
    blit_rect = player_image.get_rect()
    
    blit_rect.centerx  = self.level_data['Metadata']['Player Start'][1][0]
    blit_rect.bottom   = self.level_data['Metadata']['Player Start'][1][1]
    
    blit_rect.centerx += self.level_data['Metadata']['Player Start'][0] * 1000
    
    print blit_rect.topleft
    
    blit_rect.left    -= self.screen_pos[0] * 40
    blit_rect.top     -= self.screen_pos[1] * 40
    
    self.screen.blit(player_image,blit_rect)
    
    for cell_number in range(base_cell-3,base_cell+4):
      if cell_number < 0 or cell_number >= len(self.level_data['Cells']):
        continue
      
      for block in self.level_data['Cells'][cell_number]['Terrain']['Solid']:
        image = self.images['Terrain']['Solid'][block['Name']][0]
        
        blit_coords = list(block['Position'])
        
        blit_coords[0] -= camera_pos[0]
        blit_coords[1] -= camera_pos[1]
        
        blit_coords[0] -= ((base_cell - cell_number)*25)
        
        blit_coords[0] *= 40
        blit_coords[1] *= 40
        
        self.screen.blit(image,blit_coords)
    
    
    mouse_btns    = pygame.mouse.get_pressed()
    
    mouse_pos     = list(pygame.mouse.get_pos())
    
    mouse_pos[0] += self.screen_pos[0]
    mouse_pos[1] += self.screen_pos[1]
    
    if self.placement_mode == 'Place Terrain':
      place_pos = [0,0]
      
      for column in range(18):
        for row in range(13):
          if pygame.Rect(column*40,row*40,40,40).collidepoint(pygame.mouse.get_pos()):
            place_pos = [column,row]
      
      preview_tile = self.images['Terrain'][self.group_name()][self.tile_name()][0]
      
      preview_img  = pygame.Surface(preview_tile.get_size(),0,32)
      
      preview_img.fill((0,220,0))
      preview_img.blit(preview_tile,(0,0))
      preview_img.set_alpha(200)
      
      self.screen.blit(preview_img,[place_pos[0]*40,place_pos[1]*40])
      
      place_cell = (self.screen_pos[0] + 9) // 25
      
      place_pos[0] += (self.screen_pos[0] - (place_cell * 25))
      place_pos[1] +=  self.screen_pos[1]
      
      if   mouse_btns[0]:
        self.set_terrain_at(self.group_name(),self.tile_name(),place_cell,place_pos)
      elif mouse_btns[2]:
        self.remove_terrain_at(self.group_name(),place_cell,place_pos)
      
      # END if self.placement_mode == 'Place Terrain'
    elif self.placement_mode == 'Place Player Start':
      preview_sprite = self.images['Player']['Normal']['Idle']
      
      preview_rect = preview_sprite.get_rect()
      
      preview_rect.centerx = pygame.mouse.get_pos()[0]
      preview_rect.bottom  = pygame.mouse.get_pos()[1]
      
      self.screen.blit(preview_sprite,preview_rect.topleft)
      
      if mouse_btns[0]:
        place_pos = list(pygame.mouse.get_pos())
        place_cell = (self.screen_pos[0] + 9) // 25
      
        place_pos[0] += (self.screen_pos[0] - (place_cell * 25)) * 40
        place_pos[1] +=  self.screen_pos[1] * 40
        
        place_cell    = (self.screen_pos[0] + 9) // 25
        
        print place_cell
        
        self.level_data['Metadata']['Player Start'] = [place_cell,place_pos]
    
    message_font = pygame.font.SysFont('FreeSans,Arial',20,False,False)
    message_img  = message_font.render(self.status_message,True,(255,255,255,180))
    
    self.screen.blit(message_img,(20,20))
    
    pygame.display.update()
    
  

if __name__.lower() == '__main__':
  LevelEditor().go()
